﻿using System;
using System.Collections.Generic;
using System.Linq;
using CoyoEden.Providers;
using System.ComponentModel;

namespace CoyoEden.Models
{
	/// <summary>
	/// Album is a way to organize pictures
	/// </summary>
	[Serializable]
	public class Album:BusinessBase<Album,int>,IComparable<Album>,IPublishable
	{
		#region .ctor
		static Album() { 
			//listen to PortalFile's Saved Event
			PortalFile.Saved += new EventHandler<SavedEventArgs>(PortalFile_Saved);
		}
		public Album() {
			Id = -1;
			_Pics = new List<PortalFile>();
			_IsPublic = true;
			_IsPublished = true;
			_IsCommentEnabled = true;
			_Tags = new StateList<string>();
			_Comments = new List<Comment>();
		}
		public Album(bool isDraft) {
			if (isDraft) {
				Id =-1;
				_Pics = new List<PortalFile>();
				_Title = "";
				_Author = "";
				_Description = "";
				_Slug = "";
				_Hits = 0;
				_IsPublic = true;
				_IsPublished = true;
				_IsCommentEnabled = true;
			} else {
				new Album();
			}
		}
		#endregion

		#region member variables
		public static readonly string NoIcon = "~/assets/img/unkown80x80.gif";
		private string _Title;
		public string Title {
			get {
				return _Title;
			}
			set {
				if (_Title != value) MarkChanged("Title");
				_Title = value;
			}
		}
		private string _Author;
		/// <summary>
		/// Author profile,in Json format
		/// </summary>
		public string Author
		{
			get
			{
				if (!_AuthorProfile.Equals(null))
				{
					_Author = Utils.ToStr<SimpleAuthorProfile>(_AuthorProfile);
				}
				return _Author;
			}
			set
			{
				if (_Author != value)
				{
					MarkChanged("Author");
					_Author = value;
				}
			}
		}
		private SimpleAuthorProfile _AuthorProfile;
		public SimpleAuthorProfile AuthorProfile
		{
			get
			{
				if (!string.IsNullOrEmpty(_Author))
				{
					Utils.ToObject<SimpleAuthorProfile>(_Author, out _AuthorProfile);
				}
				return _AuthorProfile;
			}
			set
			{
				if (!_AuthorProfile.Equals(value))
				{
					MarkChanged("Author");
					_AuthorProfile = value;
				}
			}
		}
		private string _Slug;
		public string Slug {
			get { return _Slug; }
			set {
				if (_Slug != value) MarkChanged("Slug");
				_Slug = value;
			}
		}
		private int _Hits;
		public int Hits {
			get { return _Hits; }
			set {
				if (_Hits != value) MarkChanged("Hits");
				_Hits = value;
			}
		}

		private StateList<string> _Tags;
		/// <summary>
		/// An unsorted collection of tags.
		/// </summary>
		public StateList<string> Tags
		{
			get { return _Tags; }
		}
		private bool _IsPublic;
		public bool IsPublic {
			get {
				return _IsPublic;
			}
			set {
				if (_IsPublic != value) MarkChanged("IsPublic");
				_IsPublic = value;
			}
		}
		private bool _IsCommentEnabled;
		public bool IsCommentEnabled
		{
			get
			{
				return _IsCommentEnabled;
			}
			set
			{
				if (_IsCommentEnabled != value)
				{
					MarkChanged("IsCommentEnabled");
					_IsCommentEnabled = value;
				}
			}
		}
		private bool _IsPublished;
		public bool IsPublished
		{
			get
			{
				return _IsPublished;
			}
			set
			{
				if (_IsPublished != value)
				{
					MarkChanged("IsPublished");
					_IsPublished = value;
				}
			}
		}
		private readonly List<Comment> _Comments;
		public List<Comment> Comments
		{
			get { return _Comments; }
		}
		/// <summary>
		/// A collection of Approved comments for the topic sorted by date.
		/// </summary>
		public List<Comment> ApprovedComments
		{
			get
			{
				return _Comments.FindAll(c => c.IsApproved);
			}
		}

		/// <summary>
		/// A collection of comments waiting for approval for the topic, sorted by date.
		/// </summary>
		public List<Comment> NotApprovedComments
		{
			get
			{
				return _Comments.FindAll(c => !c.IsApproved);
			}
		}
		private readonly List<PortalFile> _Pics;
		public List<PortalFile> Pics {
			get {
				return _Pics;
			}
		}

		private static object _SyncRoot = new object();
		private static List<Album> _Albums;
		/// <summary>
		/// Gets an unsorted list of all Categories.
		/// </summary>
		public static List<Album> Albums {
			get {
				if (_Albums == null) {
					lock (_SyncRoot) {
						if (_Albums == null) {
							_Albums = PortalService.FillAlbums();
							_Albums.Sort();
						}
					}
				}

				return _Albums;
			}
		}
		public static List<Album> AlbumsPublic {
			get {
				var publicAlbums = from album in Albums
													 where album.IsPublic == true
													 select album;
				return publicAlbums.ToList();
			}
		}
		#endregion

		#region businessbase implementations
		protected override void ValidationRules() {
			AddRule("Title", "标题非法[标题为空或者标题已经存在]", TitleRule());
		}

		protected override Album DataSelect(int id) {
			return PortalService.SelectAlbum(id);
		}

		protected override void DataUpdate() {
			PortalService.UpdateAlbum(this);
		}

		protected override void DataInsert() {
			if (IsNew) PortalService.InsertAlbum(this);
		}

		protected override void DataDelete() {
			if (IsDeleted) PortalService.DeleteAlbum(this);
			if (Albums.Contains(this)) Albums.Remove(this);
			Dispose();
		}
		#endregion

		#region IComparable<Album> Members

		public int CompareTo(Album other) {
			return this.DateCreated.CompareTo(other.DateCreated);
		}

		#endregion

		#region helper methods
		public static List<Album> GetAlbums(string author) {
			var albums = from album in Albums
									 where album.AuthorProfile.Name == author
									 select album;
			return albums.ToList();
		}
		public static Album GetAlbum(string id) {
			if (Albums.Count == 0) return null;
			var retVal=Albums.Find(album=>album.Id.ToString()==id);
			return retVal;
		}
		public void AddPic(PortalFile pic) {
			CancelEventArgs e = new CancelEventArgs();
			OnAddingPic(pic, e);
			if (!e.Cancel)
			{
				Pics.Add(pic);
				DataUpdate();
				OnPicAdded(pic);
			}
		}
		public void ClearPics() {
			CancelEventArgs e = new CancelEventArgs();
			OnRemovingPics(e);
			if (!e.Cancel) {
				Pics.Clear();
				DataUpdate();
				OnPicsRemoved();
			}
			
		}
		/// <summary>
		/// Loads an instance of the object based on the Id.
		/// </summary>
		/// <param name="id">The unique identifier of the object</param>
		public new static Album Load(int id)
		{

			// Mono throws an invalid IL exception if this method is not overriden 
			// and handled in a non-generic fashion.

			Album instance = new Album();
			instance = instance.DataSelect(id);
			instance.Id = id;
			if (instance != null)
			{
				instance.MarkOld();
				return instance;
			}
			return null;

		}
		#endregion

		#region IPublishable Members

		public string RelativeLink
		{
			get { throw new NotImplementedException(); }
		}

		public Uri AbsoluteLink
		{
			get { throw new NotImplementedException(); }
		}

		public void OnServing(ServingEventArgs eventArgs)
		{
			throw new NotImplementedException();
		}

		public StateList<Category> Categories
		{
			get { throw new NotImplementedException(); }
		}

		public bool IsVisible
		{
			get { throw new NotImplementedException(); }
		}
		private string _Description;
		public string Description
		{
			get
			{
				return _Description;
			}
			set
			{
				if (_Description != value) MarkChanged("Description");
				_Description = value;
			}
		}
		/// <summary>
		/// Content,same as description in AN album
		/// </summary>
		public string Content
		{
			get
			{
				return _Description;
			}
		}
		#endregion

		#region business rule
		private bool TitleRule() {
			var isBroken = false;
			if (string.IsNullOrEmpty(_Title))
			{
				isBroken = true;
			}
			else {
				var tempObj = Albums.Find(a => (a.AuthorProfile.Name == _AuthorProfile.Name) && (a.Title == _Title)&&(a.Id!=Id));
				if (tempObj != null) {
					isBroken = true;
				}
			}
			return isBroken;
		}
		#endregion

		#region event handlers
		static void PortalFile_Saved(object sender, SavedEventArgs e)
		{
			if (e.Action == SaveAction.Insert || e.Action == SaveAction.None) return;

			PortalFile file = sender as PortalFile;
			//related albums
			Albums.ForEach(obj => {
				var tempFile = obj.Pics.Find(pic=>pic.Id==file.Id);
				if (null != tempFile) {
					obj.Pics.Remove(tempFile);
					if (e.Action == SaveAction.Update)
					{
						//obj.Pics.Add(file);
						obj.Pics.Insert(0, file);
					}
				}
			});

		}
		#endregion

		#region events

		/// <summary>
		/// Occurs before a new Pic is added.
		/// </summary>
		public static event EventHandler<CancelEventArgs> AddingPic;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnAddingPic(PortalFile Pic, CancelEventArgs e)
		{
			if (AddingPic != null)
			{
				AddingPic(Pic, e);
			}
		}

		/// <summary>
		/// Occurs when a Pic is added.
		/// </summary>
		public static event EventHandler<EventArgs> PicAdded;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnPicAdded(PortalFile Pic)
		{
			if (PicAdded != null)
			{
				PicAdded(Pic, new EventArgs());
			}
		}

		/// <summary>
		/// Occurs before Pic is removed.
		/// </summary>
		public static event EventHandler<CancelEventArgs> RemovingPic;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnRemovingPic(PortalFile Pic, CancelEventArgs e)
		{
			if (RemovingPic != null)
			{
				RemovingPic(Pic, e);
			}
		}

		/// <summary>
		/// Occurs when a Pic has been removed.
		/// </summary>
		public static event EventHandler<EventArgs> PicRemoved;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected virtual void OnPicRemoved(PortalFile Pic)
		{
			if (PicRemoved != null)
			{
				PicRemoved(Pic, new EventArgs());
			}
		}
		/// <summary>
		/// Occurs berfore Pics are removed
		/// </summary>
		public static event EventHandler<CancelEventArgs> RemovingPics;
		protected virtual void OnRemovingPics(CancelEventArgs e) {
			if (RemovingPics != null) {
				RemovingPics(this, e);
			}
		}
		/// <summary>
		/// Occurs when all pics have been removed;
		/// </summary>
		public static event EventHandler<EventArgs> PicsRemoved;
		protected virtual void OnPicsRemoved() {
			if (PicsRemoved != null) {
				PicsRemoved(this, new EventArgs());
			}
		}
		#endregion

	}
}
